package com.topscomm.mis.cbb.pm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.exception.MessageException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.basic.util.PrimaryKeyUtil;
import com.topscomm.cbo.pojo.CboAttachmentEntity;
import com.topscomm.cbo.pojo.CboAttachmentTypeEntity;
import com.topscomm.cbo.pojo.CboUserEntity;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmDeliverableEntity;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmProjectEntity;
import com.topscomm.mis.cbb.pm.base.pojo.CbbPmRiskEntity;
import com.topscomm.mis.cbb.pm.dto.DeliverableDeleteDto;
import com.topscomm.mis.cbb.pm.dto.DeliverableDto;
import com.topscomm.mis.cbb.pm.service.abs.AbstractDeliverableService;
import com.topscomm.pub.util.ConvertUtil;
import com.topscomm.pub.util.StringBufferProxy;
import com.topscomm.pub.util.StringUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.validation.Valid;
import javax.validation.constraints.Size;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Service
public class DeliverableService extends AbstractDeliverableService {

    @Override
    protected void beforeInsert(Map<String, Object> paramMap) throws ServiceException {
        CbbPmDeliverableEntity deliverableEntity = new CbbPmDeliverableEntity();
        deliverableEntity.convertFromMap(paramMap);
        // 获取id并赋值
        long[] arrayId = PrimaryKeyUtil.GeneIDsFromCache(deliverableEntity.getTableName(), 1);

        // 赋值单号
        if (deliverableEntity.getId() <= 0) {
            paramMap.put(CbbPmDeliverableEntity.FieldId, arrayId[0]);
            String code = String.valueOf(arrayId[0]);
            code = "JFW" + code.substring(0, 6) + code.substring(9);
            paramMap.put(CbbPmDeliverableEntity.FieldCode, code);
        }
        // 本模块新增，补充sourceType，sourceid
        if (StringUtil.isEmpty(deliverableEntity.getSourcetype())) {
            paramMap.put(CbbPmDeliverableEntity.FieldSourceid, arrayId[0]);
            paramMap.put(CbbPmDeliverableEntity.FieldSourcetype, "PmDeliverable");
            paramMap.put(CbbPmDeliverableEntity.FieldSourcemodule, "01");
        }
    }

    /**
     * description 创建交付物
     *
     * @param deliverableDto
     * @return void
     * @author wxm
     * @date 2023-06-25 18:09:07
     * @modify
     */
    @Override
    public void createDeliverable(DeliverableDto deliverableDto) {
        StringBufferProxy errorMsg = new StringBufferProxy();
        // 校验来源单据类型是否在附件中配置，校验交付物类型是否在编码中配置
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(CboAttachmentEntity.FieldSourcetype + "='{0}' ",
            deliverableDto.getSourceType()).append(" and ").append(CboAttachmentEntity.FieldEnabled)
            .append(" = 1 ");
        List<CboAttachmentTypeEntity> attachmentTypeEntityList = attachmentTypeService
            .queryByWhere(whereSql.toString());
        if (CollectionUtils.isEmpty(attachmentTypeEntityList)) {
            errorMsg.appendSingle("附件类型未配置！");
        }

        String deliverableType = datacodeCache
            .getValueDynamic("DeliverableType", deliverableDto.getSourceType(), "code",
                "name");
        if (StringUtil.isEmpty(deliverableType)) {
            errorMsg.appendSingle("交付物类型未配置！");
        }

        // 校验来源单据类型和来源单据id是否重复
        List<CbbPmDeliverableEntity> cbbPmDeliverableList = this
            .queryDeliverableBySourceTypeId(deliverableDto.getSourceType(),
                deliverableDto.getSourceId());

        if (!CollectionUtils.isEmpty(cbbPmDeliverableList)) {
            errorMsg.appendSingle("该来源单据类型和来源单据已存在！");
        }
        if (errorMsg.length() > 0) {
            throw new MessageException(errorMsg.toString());
        }

        CbbPmDeliverableEntity deliverableEntity = new CbbPmDeliverableEntity();
        BeanUtil.copyProperties(deliverableDto, deliverableEntity, true);
        // 来源模块 - 外部
        deliverableEntity.setSourcemodule("02");
        // 交付物类型 - 与sourceType保持一致
        deliverableEntity.setDeliverabletype(deliverableEntity.getSourcetype());

        // 若交付物名称为空，则默认为交付物类型名称
        if (StringUtil.isEmpty(deliverableEntity.getName())) {
            deliverableEntity.setName(deliverableType);
        }
        // 存入数据库
        this.insert(deliverableEntity.convertToMap());

    }

    /**
     * description 删除交付物
     *
     * @param sourceType
     * @param sourceId
     * @return int
     * @author wxm
     * @date 2023-06-25 18:09:20
     * @modify
     */
    @Override
    public int deleteDeliverable(String sourceType, long sourceId) {

        // 校验是否存在
        List<CbbPmDeliverableEntity> cbbPmDeliverableList = this
            .queryDeliverableBySourceTypeId(sourceType, sourceId);
        if (CollectionUtils.isEmpty(cbbPmDeliverableList)) {
            return 0;
        }
        // 按照id删除
        String ids = cbbPmDeliverableList.stream()
            .map(c -> ConvertUtil.convertToString(c.getId()))
            .collect(Collectors.joining(","));
        return cbbPmDeliverableService.deleteByIds(ids);
    }

    /**
     * description 批量创建交付物
     *
     * @param deliverableDtoList
     * @return void
     * @author wxm
     * @date 2023-06-30 16:54:39
     * @modify
     */
    @Override
    public void createDeliverableBatch(
        @Size(min = 1, message = "交付物不能为空") List<@Valid DeliverableDto> deliverableDtoList) {

        // 校验来源单据类型是否在附件中配置，校验交付物类型是否在编码中配置
        String errorMsg = this.checkAttachmentSourceType(deliverableDtoList);

        // 校验编码是否配置
        errorMsg += this.checkSourceTypeCode(deliverableDtoList);

        // 校验数据是否重复
        errorMsg += this.checkDuplication(deliverableDtoList);
        if (errorMsg.length() > 0) {
            throw new MessageException(errorMsg);
        }

        // 类型转换，存入数据库
        List<BasicEntity> deliverableEntityList = new ArrayList<>();
        for (DeliverableDto deliverableDto : deliverableDtoList) {

            CbbPmDeliverableEntity deliverableEntity = new CbbPmDeliverableEntity();
            BeanUtil.copyProperties(deliverableDto, deliverableEntity, true);
            deliverableEntity.setSourcemodule("02");
            // 来源模块 - 外部
            // 交付物类型 - 与sourceType保持一致
            deliverableEntity.setDeliverabletype(deliverableEntity.getSourcetype());
            deliverableEntityList.add(deliverableEntity);

        }
        // 存入数据库
        this.insertBatch(deliverableEntityList);
    }

    /**
     * description 批量删除
     *
     * @param deliverableDeleteDtoList
     * @return int
     * @author wxm
     * @date 2023-06-30 17:23:07
     * @modify
     */
    @Override
    public int deleteDeliverableBatch(
        @Size(min = 1, message = "数据不能为空") List<@Valid DeliverableDeleteDto> deliverableDeleteDtoList) {
        // 类型转换
        List<DeliverableDto> deliverableDtoList = new ArrayList<>();
        for (DeliverableDeleteDto deliverableDeleteDto : deliverableDeleteDtoList) {
            DeliverableDto deliverableDto = new DeliverableDto();
            deliverableDto.setSourceType(deliverableDeleteDto.getSourceType());
            deliverableDto.setSourceId(deliverableDeleteDto.getSourceId());
            deliverableDtoList.add(deliverableDto);
        }
        String whereSql = this.spellSqlBySourceTypeAndId(deliverableDtoList);
        return this.cbbPmDeliverableService.deleteByWhere(whereSql);
    }

    /**
     * description 校验数据是否重复
     *
     * @param deliverableDtoList
     * @return java.lang.String
     * @author wxm
     * @date 2023-06-30 16:42:08
     * @modify
     */
    private String checkDuplication(List<DeliverableDto> deliverableDtoList) {

        // 组装查询条件
        String whereSql = this.spellSqlBySourceTypeAndId(deliverableDtoList);

        // 查询已有交付物
        List<CbbPmDeliverableEntity> deliverableList = cbbPmDeliverableService
            .queryByWhere(whereSql);
        StringBufferProxy errorMsg = new StringBufferProxy();
        if (!CollectionUtils.isEmpty(deliverableDtoList)) {
            for (CbbPmDeliverableEntity deliverableEntity : deliverableList) {
                errorMsg
                    .appendSingle("单据类型：【{0}】，单据id：【{1}】已存在！", deliverableEntity.getSourcetype(),
                        deliverableEntity.getSourceid());
            }
        }
        return errorMsg.toString();
    }

    /**
     * description 根据sourceId和sourceType拼接sql
     *
     * @param deliverableDtoList
     * @return java.lang.String
     * @author wxm
     * @date 2023-06-30 17:16:52
     * @modify
     */
    private String spellSqlBySourceTypeAndId(List<DeliverableDto> deliverableDtoList) {
        StringBufferProxy whereSql = new StringBufferProxy();
        for (DeliverableDto deliverableDto : deliverableDtoList) {
            whereSql
                .appendSingle("(" + CbbPmDeliverableEntity.FieldSourcetype + " = '{0}' and "
                        + CbbPmDeliverableEntity.FieldSourceid + " = {1} ) or ",
                    deliverableDto.getSourceType(), deliverableDto.getSourceId());
        }
        return whereSql.substring(0, whereSql.length() - 3).toString();
    }

    /**
     * description 编码是否配置
     *
     * @param deliverableDtoList
     * @return java.lang.String
     * @author wxm
     * @date 2023-06-30 16:28:21
     * @modify
     */
    private String checkSourceTypeCode(List<DeliverableDto> deliverableDtoList) {

        // 获取交付物类型所有代码值
        List<Map<String, Object>> deliverableTypeList = datacodeCache
            .getCodeListMap("DeliverableType", "", "sortcode");
        if (CollectionUtils.isEmpty(deliverableDtoList)) {
            return "交付物类型未配置！";
        }
        // 匹配是否有缺失
        Map<String, Object> itemCodeMap = deliverableTypeList.stream().collect(Collectors
            .toMap(d1 -> ConvertUtil.convertToString(d1.get("code")), d2 -> d2.get("name")));
        StringBufferProxy errorMsg = new StringBufferProxy();
        for (DeliverableDto deliverableDto : deliverableDtoList) {
            if (!itemCodeMap.containsKey(deliverableDto.getSourceType())) {
                errorMsg.appendSingle("交付物类型未配置【{0}】！", deliverableDto.getSourceType());
            }
        }
        return errorMsg.toString();
    }

    /**
     * description 校验附件类型是否配置
     *
     * @param deliverableDtoList
     * @return java.lang.String
     * @author wxm
     * @date 2023-06-30 16:22:24
     * @modify
     */
    private String checkAttachmentSourceType(List<DeliverableDto> deliverableDtoList) {

        String sourceTypes = deliverableDtoList.stream().map(d -> "'" + d.getSourceType() + "'")
            .collect(Collectors.joining(","));
        // 查询附件管理表
        StringBufferProxy whereSql = new StringBufferProxy();
        whereSql.appendSingle(CboAttachmentEntity.FieldSourcetype + " in ( {0} ) ", sourceTypes)
            .append(" and ").append(CboAttachmentEntity.FieldEnabled)
            .append(" = 1 ");
        List<CboAttachmentTypeEntity> attachmentTypeEntityList = attachmentTypeService
            .queryByWhere(whereSql.toString());

        if (CollectionUtils.isEmpty(attachmentTypeEntityList)) {
            return "附件类型未配置！";
        }
        // 检查是否全部配置
        Map<String, CboAttachmentTypeEntity> attachmentMap = attachmentTypeEntityList.stream()
            .collect(Collectors.toMap(CboAttachmentTypeEntity::getSourcetype, Function.identity()));
        StringBufferProxy errorMsg = new StringBufferProxy();
        for (DeliverableDto deliverableDto : deliverableDtoList) {
            if (!attachmentMap.containsKey(deliverableDto.getSourceType())) {
                errorMsg.appendSingle("附件类型【{0}】未配置！", deliverableDto.getSourceType());
            }
        }
        return errorMsg.toString();
    }

    /**
     * description 根据项目号查询项目经理工号
     *
     * @param projectCode
     * @return java.lang.String
     * @author wxm
     * @date 2023-06-25 19:14:06
     * @modify
     */
    @Override
    public String queryProjectByCode(String projectCode) {
        List<Map<String, Object>> projectList = projectService.queryProjectByCode(projectCode);
        if (CollectionUtils.isEmpty(projectList)) {
            return null;
        }
        return ConvertUtil
            .convertToString(projectList.get(0).get(CbbPmProjectEntity.FieldPmcode));
    }

    /**
     * description 展示提交人
     *
     * @param mapRowList
     * @return void
     * @author wxm
     * @date 2023-06-25 18:39:38
     * @modify
     */
    @Override
    protected void setDispFields(List<Map<String, Object>> mapRowList) {

        if (CollectionUtils.isEmpty(mapRowList)) {
            return;
        }
        // 拼接创建人
        StringBufferProxy whereSql = new StringBufferProxy();
        for (Map<String, Object> map : mapRowList) {
            whereSql.appendSingle(
                ConvertUtil.convertToString(map.get(CbbPmDeliverableEntity.FieldCreateuser)))
                .append(",");
        }
        if (whereSql.length() > 0) {
            whereSql = whereSql.substring(0, whereSql.length() - 1);
            List<CboUserEntity> userEntityList = userService.queryByIds(whereSql.toString());
            if (!CollectionUtils.isEmpty(userEntityList)) {
                Map<Long, CboUserEntity> userMap = userEntityList.stream().collect(Collectors
                    .toMap(c -> ConvertUtil.convertToLong(c.getId()), Function.identity()));
                for (Map<String, Object> mapRow : mapRowList) {
                    //创建人
                    if (mapRow.get(CbbPmDeliverableEntity.FieldCreateuser) != null) {
                        Long createUserId = ConvertUtil.convertToLong(mapRow.get(
                            CbbPmDeliverableEntity.FieldCreateuser));
                        CboUserEntity cboUserEntity = userMap.get(createUserId);
                        if (cboUserEntity != null) {
                            mapRow.put("dispcreateuser", cboUserEntity.getName() +
                                "[" + cboUserEntity.getCode() + "]");
                        }
                    }
                }
            }
        }
    }

    /**
     * description 批量插入提前生成单号
     *
     * @param listEntity
     * @return void
     * @author wxm
     * @date 2023-06-30 20:14:20
     * @modify
     */
    @Override
    protected void beforeInsertBatch(List<BasicEntity> listEntity) {
        long[] arrayId = PrimaryKeyUtil
            .GeneIDsFromCache(CbbPmDeliverableEntity.tableName, listEntity.size());
        Date currentDate = new Date();
        for (int i = 0; i < listEntity.size(); i++) {
            CbbPmDeliverableEntity deliverableEntity = (CbbPmDeliverableEntity) listEntity.get(i);
            deliverableEntity.setId(arrayId[i]);
            String code = String.valueOf(arrayId[i]);
            deliverableEntity.setCode("JFW" + code.substring(0, 6) + code.substring(9));
            deliverableEntity.setCreateon(currentDate);
            deliverableEntity.setModifiedon(currentDate);
        }
    }
}